package com.game.logic.fighting.skill.skill;

import com.coment.cfg.luban.RolesSkillCfg;
import com.coment.cfg.luban.constant.AIDCFG;
import com.coment.cfg.luban.fight.DamageCfg;
import com.coment.game.fight.AttributeManagerLogic;
import com.coment.message.BuffInfo;
import com.coment.message.HurtInfo;
import com.coment.message.InjuryMessage;
import com.coment.po.roles.Roles;
import com.game.dao.user.roles.RolesDao;
import com.game.framework.lock.LooksManager;
import com.game.logic.fighting.actor.SkillInfo;
import com.game.logic.fighting.formula.InjuryFormulaBase;
import com.game.logic.fighting.skill.buff.BuffEventHandler;
import com.game.logic.fighting.skill.cd.CDHandle;
import com.xs.build.server.websocket.channel.ClientManager;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

/// 角色技能
@Slf4j
@Component
public class RolesSkillsEventHandler {
    @Resource
    private ApplicationEventPublisher eventPublisher;
    @Resource
    private RolesDao rolesDao;


    /// 技能事件
    @Getter
    public static class SkillInfoEvent extends ApplicationEvent {
        /// 技能配置
        private final RolesSkillCfg cfg;

        ///
        @Setter
        private int type;

        /// 技能信息
        @Setter
        private SkillInfo message;

        public SkillInfoEvent(Object source, RolesSkillCfg cfg) {
            super(source);
            this.cfg = cfg;
        }
    }


    /// 释放技能伤害
    public void skillHurt(SkillInfo info, RolesSkillCfg cfg) {
        DamageCfg damage = cfg.damage;
        if (damage == null) {
            return;
        }

        String spellcaster = info.getRolesId();
        Roles roles = rolesDao.findByIdMust(spellcaster);
        String[] effectOnTheEnemy = info.getEffectOnTheEnemy();
        switch (damage.hurtType) {
            case 1:
                for (String targetId : effectOnTheEnemy) {
                    roles.rolePanel.statusPanel.resetAttack();
                    ReentrantLock lock = LooksManager.getWriteLock(Roles.class, targetId);
                    lock.lock();
                    try {
                        Roles target = rolesDao.findByIdMust(targetId);
                        InjuryFormulaBase injuryFormulaBase = new InjuryFormulaBase(roles);
                        for (Double damageMultiplier : damage.percentValue) {
                            Set<Integer> fightStatus = damage.status;
                            InjuryMessage injuryMessage = injuryFormulaBase.tryHurt();
                            if (injuryMessage.isOk()) {
                                HurtInfo hurt = injuryFormulaBase.hurt(
                                        target,
                                        fightStatus,
                                        damageMultiplier / 100,
                                        damage.critBonus
                                );
                                info.hurts.add(hurt);
                            }
                        }
                        rolesDao.save(target);
                    } catch (Exception e) {
                        log.error("技能伤害异常", e);
                    } finally {
                        lock.unlock();
                    }
                }

                ClientManager.sendMessageToClient(info.getAnchorInfoId(), info);
                break;
            case 2:
                // 注册附加伤害
                InjuryFormulaBase.damageFrequencyRegistration.put(spellcaster, new InjuryFormulaBase.DamageRegistration(spellcaster, damage));
                break;
        }

        boolean b = info.hurts == null || info.hurts.stream().anyMatch(hurtInfo -> hurtInfo.hurt + hurtInfo.addHurt != 0);

        boolean existenceOfSkillEffects = cfg.endBuf != null;

        if (b && existenceOfSkillEffects) {
            if (info.isCrit()) {
                // 触发技能暴击
                SkillInfoEvent skillInfoEvent = new SkillInfoEvent(this, cfg);
                skillInfoEvent.setType(10);
                eventPublisher.publishEvent(skillInfoEvent);
            }

            // endBuff
            skillEndBUff(info, cfg);
        }
    }

    /// 技能结束附加buff
    private void skillEndBUff(SkillInfo info, RolesSkillCfg cfg) {
        if (cfg.endBuf != null) {
            double hurtSum = info.hurts.stream().mapToDouble(hurtInfo -> hurtInfo.hurt + hurtInfo.addHurt).sum();
            HashMap<String, HashMap<Double, Integer>> damageValueBonus = cfg.endBuf.damageValueBonus;
            if (damageValueBonus != null) {
                for (Map.Entry<String, HashMap<Double, Integer>> entry : damageValueBonus.entrySet()) {
                    // 奖励属性
                    Integer attrs = AttributeManagerLogic.constantsMap.get(entry.getKey());
                    // 奖励的属性值
                    for (Map.Entry<Double, Integer> value : entry.getValue().entrySet()) {
                        Double attrsValue = hurtSum * value.getKey() / 100D;
                        Integer keep = value.getValue();

                        BuffInfo buffInfo = new BuffInfo(
                                info.getSkillId(),
                                info.getRolesId(),
                                info.getRolesId(),
                                keep
                        );
                        buffInfo.addValue.merge(attrs, attrsValue, Double::sum);

                        BuffEventHandler.AttrsBuffEvent buffEvent = new BuffEventHandler.AttrsBuffEvent(this, info.getAnchorInfoId(), buffInfo);
                        eventPublisher.publishEvent(buffEvent);
                    }
                }
            }
        }
    }


    /// 技能暴击事件
    @Async
    @EventListener(classes = RolesSkillsEventHandler.SkillInfoEvent.class, condition = "#event.message?.isCrit()")
    public void skillCrit(RolesSkillsEventHandler.SkillInfoEvent event) {
        log.debug("尝试触发skillCrit: {}", event.getSource());

        // 查看是否存在前置buff
        SkillInfo message = event.getMessage();

        RolesSkillCfg cfg = event.getCfg();

        // 查看施法技能的暴击属性
        if (cfg.endBuf != null) {
            Map<Integer, Double> critBonusAttr = AttributeManagerLogic.obtainAttrs(cfg.endBuf.critBonusAttr);
            if (!critBonusAttr.isEmpty()) {
                int obtainCD = critBonusAttr.getOrDefault(AIDCFG.cd, 0.0D).intValue();
                if (obtainCD != 0) {
                    long remainingCDTime = CDHandle.getRemainingCDTime(message.getRolesId(), message.getSkillId());
                    remainingCDTime += obtainCD;
                    if (remainingCDTime > 0) {
                        CDHandle.modifySkillCD(message.getRolesId(), obtainCD);
                    }
                    log.debug("技能暴击成功--获取cd {}-->{}", obtainCD, remainingCDTime);
                }
            }
        }
    }
}
